#ifndef __M_HOST_H__
#define __M_HOST_H__
#include "queue.hpp"
#include "binding.hpp"
#include "exchange.hpp"
#include "message.hpp"

namespace zhong
{
    class VirtualHost
    {
    public:
        using ptr = std::shared_ptr<VirtualHost>;
        VirtualHost() {}
        VirtualHost(const std::string &host_name, bool durable, const std::string &data_dir, const std::string &data_file)
            : _host_name(host_name),
              _durable(durable),
              _exchange_manager(std::make_shared<ExchangeManager>(data_file)),
              _queue_manager(std::make_shared<MessageQueueManager>(data_file)),
              _binding_manager(std::make_shared<BindingManager>(data_file)),
              _message_manager(std::make_shared<MessageManager>(data_dir))
        {
            // 获取所有队列消息
            QueueMap queue_map = _queue_manager->allQueue();
            for (auto &queue : queue_map)
            {
                // 从数据文件中通过队列名获得所有的消息
                _message_manager->initQueueMessage(queue.first);
            }
        }
        bool declareExchange(const std::string &exchange_name,
                             ExchangeType type,
                             bool durable,
                             bool auto_delete,
                             const google::protobuf::Map<std::string, std::string> &args_map)
        {
            // 直接调用交换机模块内部的declareExchange
            return _exchange_manager->declareExchange(exchange_name, type, durable, auto_delete, args_map);
        }
        void deleteExchange(const std::string &exchange_name)
        {
            // 删除交换机时，需要将相关的绑定信息删除掉
            _binding_manager->removeExchangeBindings(exchange_name);
            _exchange_manager->deleteExchange(exchange_name);
        }
        bool declareQueue(const std::string &queue_name,
                          bool durable,
                          bool exclusive,
                          bool auto_delete,
                          const google::protobuf::Map<std::string, std::string> &args_map)
        {
            //
            _message_manager->initQueueMessage(queue_name);
            return _queue_manager->declareQueue(queue_name, durable, exclusive, auto_delete, args_map);
        }
        void deleteQueue(const std::string &queue_name)
        {
            //
            _message_manager->destoryQueueMessage(queue_name);
            _binding_manager->removeQueueBindings(queue_name);
            _queue_manager->deleteQueue(queue_name);
        }
        bool bind(const std::string &exchange_name, const std::string &queue_name, const std::string binding_key)
        {
            // 绑定是否持久化，需要同时判断交换机、队列的持久化
            Exchange::ptr exchange = _exchange_manager->selectExchange(exchange_name);
            if (exchange.get() == nullptr)
            {
                ERR_LOG("交换机[%s]不存在，无法绑定", exchange_name.c_str());
                return false;
            }
            MessageQueue::ptr queue = _queue_manager->selectQueue(queue_name);
            if (queue.get() == nullptr)
            {
                ERR_LOG("队列[%s]不存在，无法绑定", queue_name.c_str());
                return false;
            }
            // 注意这里最后一个参数，对应着绑定信息要持久化，对应的交换机、队列一定也要持久化
            return _binding_manager->bind(exchange_name, queue_name, binding_key, exchange->_durable && queue->_durable);
        }
        void unBind(const std::string &exchange_name, const std::string &queue_name)
        {
            return _binding_manager->unBind(exchange_name, queue_name);
        }
        QueueBindingMap exchangeBindings(const std::string &exchange_name)
        {
            return _binding_manager->getExchangeBindings(exchange_name);
        }
        QueueMap getAllQueue()
        {
            return _queue_manager->allQueue();
        }
        bool basicPublish(const std::string &queue_name, const BasicProperties *bp, const std::string &body)
        {
            MessageQueue::ptr queue = _queue_manager->selectQueue(queue_name);
            if (queue.get() == nullptr)
            {
                ERR_LOG("队列[%s]不存在，无法发布消息", queue_name.c_str());
                return false;
            }
            return _message_manager->insert(queue_name, bp, body, queue->_durable);
        }
        MessagePtr basicConsume(const std::string &queue_name)
        {
            return _message_manager->front(queue_name);
        }
        Exchange::ptr selectExchange(const std::string &exchange_name)
        {
            return _exchange_manager->selectExchange(exchange_name);
        }

        void basicAck(const std::string &queue_name, const std::string &message_id)
        {
            _message_manager->ack(queue_name, message_id);
        }
        void clear()
        {
            _exchange_manager->clear();
            _queue_manager->clear();
            _binding_manager->clear();
            _message_manager->clear();
        }

        bool existExchange(const std::string &exchange_name)
        {
            return _exchange_manager->exist(exchange_name);
        }
        bool existQueue(const std::string &queue_name)
        {
            return _queue_manager->exist(queue_name);
        }
        bool existBinding(const std::string &exchange_name, const std::string &queue_name)
        {
            return _binding_manager->exist(exchange_name, queue_name);
        }

        std::string _host_name;
        bool _durable;

    private:
        ExchangeManager::ptr _exchange_manager;
        MessageQueueManager::ptr _queue_manager;
        BindingManager::ptr _binding_manager;
        MessageManager::ptr _message_manager;
    };

    class VirtualHostMapper
    {
    public:
        VirtualHostMapper(const std::string &data_base_file) : _sqliter(data_base_file)
        {
            std::string path = Filer::parentDirectory(data_base_file); // 获取父级目录
            Filer::createDirectory(path);                              // 创建目录
            assert(_sqliter.open());                                   // 创建数据库
            createTable();
        }
        void createTable()
        {
            // 构造表的创建语句
            std::string sql_create = "create table if not exists virtualHost_table(name varchar(32) primary key,\
                                                                                    durable int);";
            if (_sqliter.exec(sql_create, nullptr, nullptr) == false)
            {
                ERR_LOG("创建虚拟机数据库失败");
                abort(); // 退出程序
            }
        }
        void removeTable()
        {
            std::string sql_remove = "drop table if exists virtualHost_table";
            if (_sqliter.exec(sql_remove, nullptr, nullptr) == false)
            {
                ERR_LOG("删除虚拟机数据库失败");
                abort(); // 退出程序
            }
        }
        bool insert(VirtualHost::ptr &host)
        {
            std::stringstream ss;
            ss << "insert into virtualHost_table values(";
            ss << "'" << host->_host_name << "', ";
            ss << "'" << host->_durable << "');";
            if (_sqliter.exec(ss.str(), nullptr, nullptr) == false)
            {
                INFO_LOG("添加虚拟机数据失败, 错误原因[%s]", strerror(errno));
                return false; // 退出程序
            }
            return true;
        }
        void remove(const std::string &host_name)
        {
            std::string sql_delete = "delete from virtualHost_table where name='" + host_name + "';";
            if (_sqliter.exec(sql_delete, nullptr, nullptr) == false)
            {
                INFO_LOG("删除虚拟机数据失败");
                return; // 退出程序
            }
        }
        std::unordered_map<std::string, VirtualHost::ptr> getAllVirtualHost()
        {
            std::unordered_map<std::string, VirtualHost::ptr> ret;
            std::string sql_select = "select name from virtualHost_table";
            _sqliter.exec(sql_select, selectCallback, &ret);
            return ret;
        }

    private:
        static int selectCallback(void *args, int numcol, char **row, char **fields)
        {
            auto ret = (std::unordered_map<std::string, VirtualHost::ptr> *)args;
            auto host = std::make_shared<VirtualHost>();
            // 按顺序添加交换机数据到ret中
            host->_host_name = row[0];
            host->_durable = (bool)std::stoi(row[1]);
            ret->insert(std::make_pair(host->_host_name, host));
            return 0;
        }

    private:
        Sqliter _sqliter;
    };

    class VirtualHostManager
    {
    public:
        using ptr = std::shared_ptr<VirtualHostManager>;
        VirtualHostManager(const std::string &data_dir) : _mapper(data_dir + "/meta.db"), _data_dir(data_dir)
        {
            _hosts = _mapper.getAllVirtualHost(); // 获取所有虚拟机
        }
        bool declareVirtualHost(const std::string &host_name, bool durable)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _hosts.find(host_name);
            if (it != _hosts.end())
            {
                INFO_LOG("虚拟机[%s]已存在", host_name.c_str());
                return true;
            }
            // 设置host中的exchange、queue、message的存储格式
            // 目的是实现：
            std::string host_dir = _data_dir;
            host_dir += host_name;
            host_dir += "/";

            VirtualHost::ptr host = std::make_shared<VirtualHost>(host_name, durable, host_dir, host_dir + "/meta.db");
            if (host->_durable == true)
            {
                _mapper.insert(host);
            }
            _hosts.insert(std::make_pair(host_name, host));
            return true;
        }
        void deleteVirtualHost(const std::string &host_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _hosts.find(host_name);
            if (it == _hosts.end())
            {
                INFO_LOG("虚拟机[%s]不存在，无法删除", host_name.c_str());
                return;
            }
            if (it->second->_durable == true) // 为false不需要刻意删除，因为并没有加载到数据库中
                _mapper.remove(host_name);
            _hosts.erase(host_name);
        }
        VirtualHost::ptr selectVirtualHost(const std::string &host_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _hosts.find(host_name);
            if (it == _hosts.end())
            {
                INFO_LOG("虚拟机[%s]不存在", host_name.c_str());
                return VirtualHost::ptr();
            }
            return it->second;
        }
        bool exist(const std::string &host_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _hosts.find(host_name);
            if (it == _hosts.end())
            {
                return false;
            }
            return true;
        }
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _hosts.size();
        }
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();
            _hosts.clear();
        }

    private:
        std::mutex _mutex;
        std::string _data_dir;
        VirtualHostMapper _mapper;
        std::unordered_map<std::string, VirtualHost::ptr> _hosts;
    };
}
#endif